{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Keysight M3202A AWG example with digitizer" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The Keysight M3202A is a 1 GSa/a arbitrary waveform generator.\n", "\n", "An instance of M3202A represents a module with 4 output channels. The channels of one module share the uploaded waveforms and trigers.\n", "\n", "This example loads loads waveforms in AWGs in slots 2 and 3 of chassis 0.\n", "\n", "This example uses a digitizer from the keysightSD1 module to read the generated signals. The digitizer is in slot 5. The output channels 1 and 2 of the AWG in slot 2 should be connected to inputs 1 and 2 of the digitizer and output channels 3 and 4 of the AWG slot 3 should be conencted to inputs 3 and 4 of the digitizer." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import logging\n", "\n", "import numpy as np\n", "import matplotlib.pyplot as plt\n", "\n", "try:\n", " import keysightSD1\n", "except:\n", " # add the path where the keysight library probably resides and try again\n", " import sys\n", " sys.path.append(r'C:\\Program Files (x86)\\Keysight\\SD1\\Libraries\\Python')\n", " import keysightSD1\n", "\n", "import qcodes\n", "from qcodes_contrib_drivers.drivers.Keysight.M3202A import M3202A\n", "\n", "import qcodes.logger as logger\n", "from qcodes.logger import start_all_logging\n", "\n", "start_all_logging()\n", "# logger.get_file_handler().setLevel(logging.DEBUG)\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# try to close station from previous run.\n", "try:\n", " station.close_all_registered_instruments()\n", "except: pass" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Demonstration of some errors\n", "try:\n", " wrong_chassis = M3202A(\"wrong chassis\", chassis = 5, slot = 16)\n", "except Exception as e: \n", " print('Expected failure:', e)\n", " \n", "try:\n", " empty_slot = M3202A(\"empty_slot\", chassis = 0, slot = 16)\n", "except Exception as e: \n", " print('Expected failure:', e)\n", "\n", "try:\n", " not_M3202A = M3202A(\"Digitizer\", chassis = 0, slot = 5)\n", "except Exception as e: \n", " print('Expected failure:', e) " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "awg1 = M3202A(\"AWG1\", chassis = 0, slot = 2)\n", "awg2 = M3202A(\"AWG2\", chassis = 0, slot = 3)\n", "\n", "station = qcodes.Station()\n", "\n", "station.add_component(awg1)\n", "station.add_component(awg2)\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# utility functions to create waveforms\n", "\n", "def get_divider(prescaler):\n", " if prescaler == 0:\n", " divider = 1\n", " elif prescaler == 1:\n", " divider = 5\n", " else:\n", " divider = prescaler * 10\n", " \n", " return divider\n", "\n", "def create_sawtooth(period, repetition, prescaler):\n", " divider = get_divider(prescaler)\n", " n_pts = period // divider\n", " w = np.linspace(-1, 1, n_pts)\n", " w = np.tile(w, repetition)\n", " \n", " if len(w) < 2000:\n", " raise Exception('not enough data')\n", " \n", " return w\n", "\n", "def create_sine(period, repetition, prescaler):\n", " divider = get_divider(prescaler)\n", " n_pts = repetition * period // divider\n", " phi = np.linspace(0, np.pi*2*repetition, n_pts)\n", " w = np.sin(phi)\n", " \n", " if len(w) < 2000:\n", " raise Exception('not enough data')\n", " \n", " return w\n", " " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# setup output channels\n", "\n", "pxi1 = keysightSD1.SD_TriggerExternalSources.TRIGGER_PXI1\n", "trigger_mode = keysightSD1.SD_TriggerBehaviors.TRIGGER_FALL\n", "\n", "for awg in [awg1, awg2]:\n", " for ch in range(1,5): \n", " awg.set_channel_offset(0.0, ch)\n", " awg.set_channel_amplitude(1.0, ch)\n", " \n", " awg.set_channel_wave_shape(keysightSD1.SD_Waveshapes.AOU_AWG, ch)\n", " awg.awg_queue_config(ch, keysightSD1.SD_QueueMode.CYCLIC)\n", " awg.awg_config_external_trigger(ch, pxi1, trigger_mode)\n", "\n", "awg2.amplitude_channel_1.set(0.5)\n", "awg2.offset_channel_2.set(0.5)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Generate and enqueue waveforms\n", "Signal duration 20 us:\n", "* \"AWG1.1\": 20x sawtooth (followed by zeros)\n", "* \"AWG1.2\": 20 steps (followed by zeros)\n", "* \"AWG2.3\": 2 us zero, 4 us sine, 2 us zero, 12 us sine\n", "* \"AWG2.4\": 4 us sine, 4 us zero, 8 us sine, 4 us zero\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "prescaler_1GSa = 0\n", "prescaler_200MSa = 1\n", "prescaler_50MSa = 2\n", "\n", "# 2000 zero's for end\n", "zeros = np.zeros(2000)\n", "\n", "# sawtooth period = 1 us: 2 period in 1 sample\n", "sawtooth_2us = 0.5 * create_sawtooth(1000, 2, prescaler_1GSa)\n", "# 20 steps use prescaler to reduce total number of samples. 200MSa/s => 4000 pts; 200 per step\n", "steps = np.concatenate([0.02*i*np.ones(200) for i in range(20)])\n", "\n", "# sine wave 2 MHz, 4 periods\n", "sine = 0.6 * create_sine(500, 4, prescaler_1GSa)\n", "\n", "# start all uploads\n", "zeros_awg1 = awg1.upload_waveform(zeros)\n", "sawtooth_2us_awg1 = awg1.upload_waveform(sawtooth_2us)\n", "steps_awg1 = awg1.upload_waveform(steps)\n", "\n", "zeros_awg2 = awg2.upload_waveform(zeros)\n", "sine_awg2 = awg2.upload_waveform(sine)\n", "\n", "# enqueue wave references\n", "delay = 0\n", "ext_trigger = keysightSD1.SD_TriggerModes.EXTTRIG\n", "auto_trigger = keysightSD1.SD_TriggerModes.AUTOTRIG\n", "\n", "awg1.awg_queue_waveform(1, sawtooth_2us_awg1, ext_trigger, delay, 10, prescaler_1GSa)\n", "awg1.awg_queue_waveform(1, zeros_awg1, auto_trigger, delay, 1, prescaler_1GSa)\n", "\n", "awg1.awg_queue_waveform(2, steps_awg1, ext_trigger, delay, 1, prescaler_200MSa)\n", "awg1.awg_queue_waveform(2, zeros_awg1, auto_trigger, delay, 1, prescaler_1GSa)\n", "\n", "awg2.awg_queue_waveform(3, zeros_awg2, ext_trigger, delay, 1, prescaler_1GSa)\n", "awg2.awg_queue_waveform(3, sine_awg2, auto_trigger, delay, 2, prescaler_1GSa)\n", "awg2.awg_queue_waveform(3, zeros_awg2, auto_trigger, delay, 1, prescaler_1GSa)\n", "awg2.awg_queue_waveform(3, sine_awg2, auto_trigger, delay, 6, prescaler_1GSa)\n", "\n", "awg2.awg_queue_waveform(4, sine_awg2, ext_trigger, delay, 2, prescaler_1GSa)\n", "awg2.awg_queue_waveform(4, zeros_awg2, auto_trigger, delay, 2, prescaler_1GSa)\n", "awg2.awg_queue_waveform(4, sine_awg2, auto_trigger, delay, 4, prescaler_1GSa)\n", "awg2.awg_queue_waveform(4, zeros_awg2, auto_trigger, delay, 2, prescaler_1GSa)\n", "\n", "# start AWGs. They will wait for external trigger.\n", "awg1.awg_start_multiple(0b0011)\n", "awg2.awg_start_multiple(0b1100)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### configure digitizer to capture signals " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "\n", "\n", "def check_error(error, s=''):\n", " if (type(error) is int and error < 0):\n", " print(keysightSD1.SD_Error.getErrorMessage(error), error, s)\n", "\n", "\n", "PRODUCT = \"\"\n", "CHASSIS = 0\n", "\n", "# change slot numbers to your values\n", "SLOT_IN = 5\n", "\n", "NUM_CHANNELS = 4\n", "\n", "# CREATE AND OPEN MODULE IN\n", "moduleIn = keysightSD1.SD_AIN()\n", "\n", "moduleInID = moduleIn.openWithSlot(PRODUCT, CHASSIS, SLOT_IN)\n", "\n", "NUM_CYCLES = 1\n", "DIG_PRESCALER = 0\n", "\n", "# sample 21 us\n", "IN_DURATION = 21\n", "TOT_POINTS_IN = 500 * IN_DURATION\n", "\n", "FULL_SCALE = 2.5\n", "\n", "DELAY_IN = 200 // (DIG_PRESCALER + 1)\n", "\n", "mask = 0\n", "\n", "for ch in range(1,5):\n", " moduleIn.DAQstop(ch)\n", " moduleIn.DAQflush(ch)\n", "\n", "for c in range(0, NUM_CHANNELS):\n", " mask |= 1 << c\n", " ch = c + 1\n", "\n", " # MODULE IN\n", " moduleIn.channelInputConfig(ch, FULL_SCALE, keysightSD1.AIN_Impedance.AIN_IMPEDANCE_HZ, keysightSD1.AIN_Coupling.AIN_COUPLING_DC)\n", " moduleIn.channelPrescalerConfig(ch, DIG_PRESCALER)\n", " moduleIn.DAQdigitalTriggerConfig(ch, pxi1, trigger_mode)\n", " moduleIn.DAQconfig(ch, TOT_POINTS_IN, 1, DELAY_IN, ext_trigger)\n", "\n", "moduleIn.DAQstartMultiple(mask)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Trigger AWGs and digitizer" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# start AWGs and digitizers via PXI\n", "# Note: PXI trigger can be set via any module\n", "awg1.set_pxi_trigger(0, pxi1)\n", "awg1.set_pxi_trigger(1, pxi1)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Retrieve digitizer data and plot result" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "\n", "POINTS_PER_READ = 20000\n", "\n", "READ_TIMEOUT = 1000\n", "\n", "numReadPoints = []\n", "dataPoints = []\n", "\n", "for c in range(0, NUM_CHANNELS):\n", " numReadPoints.append(0)\n", " dataPoints.append(np.empty(0, dtype=np.short))\n", "\n", "readDone = False\n", "\n", "print()\n", "print(\"Reading data...\")\n", "\n", "cnt = 0\n", "while not readDone:\n", "\n", " if (cnt > 10):\n", " print('no more data')\n", " break\n", "\n", " readDone = True\n", " for c in range(0, NUM_CHANNELS):\n", " npts = moduleIn.DAQcounterRead(c + 1)\n", " if npts <= 0:\n", " print(f'channel {c} counter {npts} {numReadPoints[c]}')\n", " cnt += 1\n", "\n", " else:\n", " readPoints = moduleIn.DAQread(c + 1, min(POINTS_PER_READ, npts), READ_TIMEOUT)\n", "\n", " check_error(readPoints)\n", "\n", " if type(readPoints) is int or readPoints.size == 0:\n", " cnt += 1\n", " else:\n", " cnt = 0\n", " dataPoints[c] = np.append(dataPoints[c], readPoints)\n", "\n", " numReadPoints[c] += readPoints.size\n", "\n", " print(f'channel {c} counter {npts} read {readPoints.size} ({numReadPoints[c]})')\n", "\n", " readDone = readDone and (numReadPoints[c] >= TOT_POINTS_IN)\n", "\n", "\n", "for i in range(1,5):\n", " fig = plt.figure(i)\n", " fig.clear()\n", " plt.plot(dataPoints[i-1])\n", " plt.show() " ] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (Spyder)", "language": "python3", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.6.10" }, "nbsphinx": { "execute": "never" } }, "nbformat": 4, "nbformat_minor": 2 }